package panda.log;

import java.util.Iterator;

import panda.file.Block;
import panda.file.Page;
import panda.server.Panda;

public class LogManager implements Iterable<BasicLogRecord> {
	private Page page = new Page();

	private String logFileName;

	private Block currentBlock;

	private int currentPosition;

	public LogManager(String logFileName) {
		this.logFileName = logFileName;
		int logFileSize = Panda.getFileManager().size(logFileName);
		if (logFileSize == 0) {
			appendNewBlock();
		} else {
			assignToBlock(logFileSize);
		}
	}

	private void assignToBlock(int logFileSize) {
		currentBlock = new Block(logFileName, logFileSize - 1);
		page.read(currentBlock);
		currentPosition = getPointer() + Page.INT_SIZE;
	}

	public synchronized int append(Object[] record) {
//		int recordSize = Page.INT_SIZE;
//		for (Object obj : record)
//			recordSize += getSize(obj);
//		if (currentPosition + recordSize >= Block.BLOCK_SIZE) {
//			flush(currentPosition);
//			appendNewBlock();
//		}
//		for (Object object : record)
//			appendObject(object);
//		closeChain();
		return currentLSN();
	}

	private void closeChain() {
		page.putInt(currentPosition, getPointer());
		setPointer(currentPosition);
		currentPosition += Page.INT_SIZE;

	}

	private void appendObject(Object object) {
		if (object instanceof String) {
			page.putString(currentPosition, (String) object);
		} else if (object instanceof Integer) {
			page.putInt(currentPosition, (Integer) object);
		} else if (object instanceof Float) {
			page.putFloat(currentPosition, (Float) object);
		} else if (object instanceof Long) {
			page.putLong(currentPosition, (Long) object);
		} else if (object instanceof Byte[]){
			page.putArray(currentPosition, (byte[])object);
		}
		currentPosition += getSize(object);

	}

	private int getSize(Object object) {
		if (object instanceof String) {
			return Page.STR_SIZE((String) object);
		} else if (object instanceof Integer) {
			return Page.INT_SIZE;
		} else if (object instanceof Float) {
			return Page.FLOAT_SIZE;
		} else if (object instanceof Long) {
			return Page.LONG_SIZE;
		} else if (object instanceof Byte[]){
			return Page.ARRAY_SIZE((byte[]) object);
		}
		return -1;
	}

	private int getPointer() {
		return page.getInt(0);
	}

	private void appendNewBlock() {
		setPointer(0);
		currentPosition = Page.INT_SIZE;
		currentBlock = page.append(logFileName);
	}

	private void setPointer(int pointer) {
		page.putInt(0, pointer);
	}

	public Iterator<BasicLogRecord> iterator() {
		flush(currentLSN());
		return new LogIterator(currentBlock);
	}

	public int getLSN(Block block) {
		return block.getBlockNumber();
	}

	public int currentLSN() {
		return currentBlock.getBlockNumber();
	}

	public void flush(int lsn) {
		if (lsn >= currentLSN()) {
			page.write(currentBlock);
		}
	}
}
